package com.core.shared.encrypt;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * Created with IntelliJ IDEA.
 * User: lxf
 * Date: 2016/9/19
 * Time: 11:38
 * To change this template use Editor | File and Code Templates.
 */
public class PEncryptUtil {

    private static final String algorithm = "DES"; // 定义 加密算法,可用DES,DESede,Blowfish
    private static final String key = "lxfqskf!&*$,.098*";

    /**
     * 加密
     *
     * @param plainText
     * @return
     */
    public static String encrypt(String plainText) {
        // 添加新安全算法,如果用JCE就要把它添加进去
        Security.addProvider(new com.sun.crypto.provider.SunJCE());
        try {
            // 生成密钥
            SecretKey deskey = getKey(key, algorithm);
            // 加密
            Cipher c1 = Cipher.getInstance(algorithm);
            c1.init(Cipher.ENCRYPT_MODE, deskey);
            byte[] cipherByte = c1.doFinal(plainText.getBytes());
            String result = new BASE64Encoder().encode(cipherByte);
            result = handleAndencrypt(result, key);
            return result;
        } catch (java.security.NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (java.lang.Exception e3) {
            e3.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     *
     * @param encryptString
     * @return
     */
    public static String decrypt(String encryptString) {
        // 添加新安全算法,如果用JCE就要把它添加进去
        Security.addProvider(new com.sun.crypto.provider.SunJCE());
        try {
            encryptString = handleAnddecrypt(encryptString, key);

            byte[] cipherByte = new BASE64Decoder().decodeBuffer(encryptString);

            // 生成密钥
            SecretKey deskey = getKey(key, algorithm);
            // 解密
            Cipher c1 = Cipher.getInstance(algorithm);
            c1.init(Cipher.DECRYPT_MODE, deskey);
            byte[] clearByte = c1.doFinal(cipherByte);

            String result = new String(clearByte);
            return result;
        } catch (java.security.NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (java.lang.Exception e3) {
            e3.printStackTrace();
        }
        return null;
    }

    /**
     * 获取秘钥
     *
     * @param key
     * @param algorithm
     * @return
     * @throws InvalidKeyException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    private static SecretKey getKey(String key, String algorithm) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
        DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
        SecretKey deskey = keyFactory.generateSecret(desKeySpec);
        return deskey;
    }


    /**
     * 处理字符串（进一步加密）：
     * 1.字符串每个字符后面添加10位随机字符（0-9a-zA-Z）；
     * 2.字符串反转；
     * 3.字符串尾添加密钥key；
     * 4.字符串首5位字符与尾5位字符调换；
     * 5.字符串首尾添加两个随机数（0-9a-zA-Z）。
     *
     * @param src
     * @return
     */
    private static String handleAndencrypt(String src, String key) {
        if (src == null || src.length() == 0 || key == null
                || key.length() == 0) {
            return src;
        }
        StringBuilder targetSrc = new StringBuilder(src);
        //添加10位随机串
        targetSrc.append(random(10));
        //字符串反转
        targetSrc.reverse();
        //添加密钥
        targetSrc.append(key);
        //字符串前5位
        String first = targetSrc.substring(0, 5);
        //中间数据
        String middle = targetSrc.substring(5, targetSrc.length() - 5);
        //字符串后5位
        String last = targetSrc.substring(targetSrc.length() - 5);
        targetSrc.delete(0, targetSrc.length());
        //前后替换 第4步
        targetSrc.append(last).append(middle).append(first);
        String temp = targetSrc.toString();
        targetSrc.delete(0, targetSrc.length());
        //首尾添加10个随机字符串
        targetSrc.append(random(10)).append(temp).append(random(10));
        return targetSrc.toString();
    }

    /**
     * 解密算法：
     * 1.字符串首尾去掉10个字符；
     * 2.字符串首5位字符与尾5位字符调换；
     * 3.字符串去掉尾部密钥key；
     * 4.字符串反转；
     * 5.从第一个字符开始，每个字符后面去掉两个字符。
     *
     * @param src
     * @return
     */
    private static String handleAnddecrypt(String src, String key) {
        if (src == null || src.length() == 0 || key == null
                || key.length() == 0) {
            return src;
        }
        //去掉字符串首尾10个随机字符串
        String tempSrc = src.substring(10, src.length() - 10);

        //首尾5个字符串进行调换
        String first = tempSrc.substring(0, 5);
        String middle = tempSrc.substring(5, tempSrc.length() - 5);
        String last = tempSrc.substring(tempSrc.length() - 5);
        StringBuilder targetSrc = new StringBuilder();
        targetSrc.append(last).append(middle).append(first);

        //去掉加密密钥
        String temp = targetSrc.substring(0, targetSrc.length() - key.length());
        targetSrc.delete(0, targetSrc.length());
        targetSrc.append(temp);
        //字符串反转
        targetSrc.reverse();

        //去掉尾部10位随机字符串
        temp = targetSrc.substring(0, targetSrc.length() - 10);
        targetSrc.delete(0, targetSrc.length());
        targetSrc.append(temp);
        return targetSrc.toString();
    }

    private static String random(int tokenLen) {
        if (tokenLen < 1) {
            tokenLen = 1;
        }
        StringBuilder buffer = new StringBuilder("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
        StringBuilder sb = new StringBuilder();
        Random r = new Random();
        int range = buffer.length();
        for (int i = 0; i < tokenLen; i++) {
            sb.append(buffer.charAt(r.nextInt(range)));
        }
        return sb.toString();
    }


}
